/*
 * ECARX Technology Limited is the owner of the copyright and the trade secret of this software.
 * Without permission, no one has the right to obtain, disclose or use this software in any way.
 */

package com.ecarx.systemui.plugin.model.wifi;

import android.annotation.SuppressLint;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.MacAddress;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiNetworkSpecifier;
import android.net.wifi.WifiNetworkSuggestion;
import android.os.Build;
import android.text.TextUtils;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;

import com.ecarx.systemui.plugin.controller.WifiController;
import com.ecarx.systemui.plugin.utils.LogUtils;
import com.ecarx.systemui.plugin.PluginContext;
import com.ecarx.systemui.plugin.utils.WifiUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class WifiImpl implements IWifiApi {

    private static WifiImpl mWifiImpl;
    private WifiManager manager;
    private ConnectivityManager connectivityManager;

    public static final String TAG = WifiImpl.class.getSimpleName();

    public static WifiImpl getInstance() {
        if (mWifiImpl == null) {
            mWifiImpl = new WifiImpl();
        }
        return mWifiImpl;
    }

    private WifiImpl() {
        Context hostAppContext = PluginContext.getContextByActThread();
        if (hostAppContext == null) {
            LogUtils.e(TAG, "getContextByActThread IS NULL");
            return;
        }
        manager = (WifiManager) hostAppContext.getSystemService(Context.WIFI_SERVICE);
        connectivityManager = (ConnectivityManager) hostAppContext.getSystemService(Context.CONNECTIVITY_SERVICE);
    }

    @Override
    public WifiController.WifiState getWifiState() {
        if (manager == null) {
            return WifiController.WifiState.DISABLE;
        }
        int state = manager.getWifiState();
        switch (state) {
            case WifiManager.WIFI_STATE_ENABLING:
            case WifiManager.WIFI_STATE_ENABLED:
                return WifiController.WifiState.OPEN;
            case WifiManager.WIFI_STATE_DISABLING:
            case WifiManager.WIFI_STATE_DISABLED:
                return WifiController.WifiState.CLOSE;
        }
        return WifiController.WifiState.DISABLE;
    }

    @Override
    public void openWifi(IWifiResult result) {
        if (manager != null) {
            manager.setWifiEnabled(true);
            manager.startScan();
        }
    }

    @Override
    public void closeWifi(IWifiResult result) {
        if (manager != null) {
            manager.setWifiEnabled(false);
        }
    }

    @Override
    public List<WifiItemBean> getConnectedInfoList() {
        return null;
    }

    @RequiresApi(api = Build.VERSION_CODES.TIRAMISU)
    @SuppressLint("MissingPermission")
    @Override
    public List<WifiItemBean> getScanInfoList() {
        if (manager == null) {
            return new ArrayList<>();
        }
        WifiInfo connectionInfo = manager.getConnectionInfo();
        boolean connect = connectionInfo != null;
        List<ScanResult> resultList = manager.getScanResults();
        List<WifiItemBean> list = resultList.stream().filter(scanResult ->
                !TextUtils.isEmpty(scanResult.SSID) && connect && !connectionInfo.getSSID().equals(scanResult.SSID))
                .flatMap(((Function<ScanResult, Stream<WifiItemBean>>) scanResult -> {
                    WifiItemBean bean = new WifiItemBean();
                    bean.name = scanResult.SSID;
                    bean.signal = manager.calculateSignalLevel(scanResult.level);
                    bean.locked = WifiUtils.isWifiSecurity(scanResult.capabilities);
                    bean.BSSID = scanResult.BSSID;
                    bean.ssid = scanResult.SSID;
                    bean.lockType = WifiUtils.getWifiSecurityType(scanResult.capabilities);
                    return Stream.of(bean);
                })).sorted((bean, t1) -> bean.signal > t1.signal ? 1 : 0).distinct().collect(Collectors.toList());
        LogUtils.d(TAG, "list SIZE:" + list.size());
        return list;
    }

    @RequiresApi(api = Build.VERSION_CODES.TIRAMISU)
    @SuppressLint("MissingPermission")
    @Override
    public void connect(WifiItemBean bean, IWifiResult result) {
        if (manager == null) {
            return;
        }
        List<WifiConfiguration> configurationList = manager.getConfiguredNetworks();
        boolean connectedBefore = false;
        boolean connected = false;
        WifiConfiguration connectedConfig = null;
        for (WifiConfiguration wifiConfiguration : configurationList) {
            if (wifiConfiguration.SSID.replace("\"", "").equals(bean.ssid)) {
                connectedBefore = true;
                connectedConfig = wifiConfiguration;
                break;
            }
        }
//        if (connectedBefore) {
//            connected = manager.enableNetwork(connectedConfig.networkId, true);
//        } else {
        WifiConfiguration wifiConfig = createWifiConfig(bean);
        int netId = manager.addNetwork(wifiConfig);
        connected = manager.enableNetwork(netId, true);
//        }
//        if (connected) {
//            result.onSuccess("");
//        } else {
//            result.onError("");
//        }

        LogUtils.e(TAG, "start connect " + bean + "result:" + connected);

    }

    @RequiresApi(api = Build.VERSION_CODES.Q)
    private void connect(WifiItemBean bean) {
        if (connectivityManager == null) {
            return;
        }
        WifiNetworkSpecifier.Builder networkSpecifier = new WifiNetworkSpecifier.Builder()
                .setSsid(bean.ssid)
                .setBssid(MacAddress.fromString(bean.BSSID));
        if (bean.locked) {
//            if (bean.lockType == WifiUtils.WifiCapability.WIFI_WPA) {
//                networkSpecifier.setWpa3Passphrase(bean.password);
//            } else {
            networkSpecifier.setWpa2Passphrase(bean.password);
//            }
        }
        NetworkRequest networkRequest = new NetworkRequest.Builder()
                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                .setNetworkSpecifier(networkSpecifier.build())
                .build();
        connectivityManager.requestNetwork(networkRequest, new ConnectivityManager.NetworkCallback() {
            @Override
            public void onAvailable(@NonNull Network network) {
                super.onAvailable(network);
                if (connectivityManager.getBoundNetworkForProcess() != network) {
                    connectivityManager.bindProcessToNetwork(network);
                }
                LogUtils.e(TAG, "start connect onAvailable");
            }

            @Override
            public void onUnavailable() {
                super.onUnavailable();
                LogUtils.e(TAG, "start connect onUnavailable");
            }
        });
    }

    @RequiresApi(api = Build.VERSION_CODES.Q)
    private void connectByP2P(String ssid, String password) {
        if (connectivityManager == null) {
            return;
        }
        WifiNetworkSpecifier specifier = new WifiNetworkSpecifier.Builder()
                .setSsid(ssid)
                .setWpa2Passphrase(password)
                .build();
        NetworkRequest request =
                new NetworkRequest.Builder()
                        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                        .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                        .setNetworkSpecifier(specifier)
                        .build();

        ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
            @Override
            public void onAvailable(Network network) {
            }

            @Override
            public void onUnavailable() {
            }
        };
        connectivityManager.requestNetwork(request, networkCallback);
    }

    //Android10以上，通过suggestion连接WIFI
    @SuppressLint("MissingPermission")
    @RequiresApi(api = Build.VERSION_CODES.Q)
    private void connectBySug(String ssid, String password) {
        if (manager == null) {
            return;
        }
        WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
                .setSsid(ssid)
                .setWpa2Passphrase(password)
                .setIsAppInteractionRequired(true)
                .build();
        //wifiManager.removeNetworkSuggestions(suggestionsList)
        ArrayList<WifiNetworkSuggestion> list = new ArrayList<>();
        list.add(suggestion);
        int status = manager.addNetworkSuggestions(list);
        LogUtils.e(TAG, "status:" + status);
    }

    @SuppressLint("MissingPermission")
    private WifiConfiguration createWifiConfig(WifiItemBean bean) {
        WifiConfiguration configuration = new WifiConfiguration();
        configuration.allowedAuthAlgorithms.clear();
        configuration.allowedGroupCiphers.clear();
        configuration.allowedKeyManagement.clear();
        configuration.allowedPairwiseCiphers.clear();
        configuration.allowedProtocols.clear();
        configuration.SSID = "\"" + bean.ssid + "\"";
        if (manager == null) {
            return configuration;
        }
        for (WifiConfiguration configuredNetwork : manager.getConfiguredNetworks()) {
            if (configuredNetwork.SSID.equals(configuration.SSID)) {
                manager.removeNetwork(configuredNetwork.networkId);
                manager.saveConfiguration();
                break;
            }
        }
        if (bean.locked) {

        } else {
            configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
        }
        return configuration;
    }

    @Override
    public void disconnect(WifiItemBean bean, IWifiResult result) {

    }

    @Override
    public void forget(WifiItemBean bean, IWifiResult result) {

    }

    @RequiresApi(api = Build.VERSION_CODES.R)
    @Override
    public WifiItemBean connected() {
        if (manager == null) {
            return null;
        }
        WifiInfo connectionInfo = manager.getConnectionInfo();
        if (connectionInfo == null) {
            return null;
        }
        WifiItemBean bean = new WifiItemBean();
        bean.name = connectionInfo.getSSID();
        bean.signal = manager.calculateSignalLevel(connectionInfo.getRssi());
        return bean;
    }
}
